home *** CD-ROM | disk | FTP | other *** search
- /* File MSNARP.C
- * ARP and RARP packet processor
- *
- * Copyright (C) 1991, University of Waterloo.
- * Copyright (C) 1985, 1993, Trustees of Columbia University in the
- * City of New York. Permission is granted to any individual or institution
- * to use this software as long as it is not sold for profit. This copyright
- * notice must be retained. This software may not be included in commercial
- * products without written permission of Columbia University.
- *
- * Original version created by Erick Engelke of the University of
- * Waterloo, Waterloo, Ontario, Canada.
- * Adapted and modified for MS-DOS Kermit by Joe R. Doupnik,
- * Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
- *
- * Last edit
- * 18 Dec 1992 v3.13
- *
- * Address Resolution Protocol
- *
- * Externals:
- * ap_handler(pb) - returns 1 on handled correctly, 0 on problems
- * arp_resolve - rets 1 on success, 0 on fail
- * - does not return hardware address if passed NULL for buffer
- *
- */
- #include "msntcp.h"
- #include "msnlib.h"
-
- #ifdef KERMIT
- #define MAX_ARP_DATA 10
- #else
- #define MAX_ARP_DATA 40
- #endif /* KERMIT */
-
- #define NEW_EXPIRY
- #define MAX_ARP_ALIVE 300 /* five minutes */
- #define MAX_ARP_GRACE 100 /* additional grace upon expiration */
- #define PLEN 4 /* bytes in an IP address longword */
-
- eth_address eth_none = { 0,0,0 };
-
- /* ARP and RARP header. Note that address lengths and hardware type ident
- vary depending on frame type at the hardware level. The frame handler
- (Packet Driver or ODI driver) will set these values. jrd */
-
- typedef struct {
- word hwType; /* hardware type ident */
- word protType; /* protocol ident */
- byte hlen; /* length of MAC hardware address */
- byte plen; /* plen, length of protocol address */
- word opcode;
- byte addr[6+6+2*PLEN]; /* address fields, frame dependent */
- } arp_header;
-
- typedef struct
- {
- longword ip;
- eth_address hardware;
- byte flags;
- byte bits; /* bits in network */
- longword expiry;
- } arp_tables;
-
- typedef struct
- {
- longword gate_ip;
- longword subnet;
- longword mask;
- } gate_tables;
-
- /* ARP style op codes */
- #define ARP_REQUEST 0x0100
- #define ARP_REPLY 0x0200
- #define RARP_REQUEST 0x0300 /* RARP request */
- #define RARP_REPLY 0x0400 /* RARP reply */
-
- #define ARP_FLAG_NEED 0
- #define ARP_FLAG_FOUND 1
- #define ARP_FLAG_FIXED 255 /* cannot be removed */
- extern longword ipbcast; /* IP broadcast address */
- /* MAC_len and arp_hardware can be set by the packet frame routines */
- word MAC_len = 6; /* bytes in MAC level hardware addr */
- word arp_hardware = 0x0001; /* ARP, hardware ident, little end */
- /*
- * arp resolution cache - we zero fill it to save an initialization routine
- */
-
- static arp_tables arp_data[MAX_ARP_DATA];
- gate_tables arp_gate_data[MAX_GATE_DATA];
- word arp_last_gateway = 0;
- static word arp_index = 0; /* rotates round-robin */
-
- /*
- * arp_add_gateway - if data is NULL, don't use string
- */
- void
- arp_add_gateway(byte *data, longword ip)
- {
- word i;
- register byte *subnetp, *maskp;
- longword subnet, mask;
-
- if ((data == NULL) && (ip == 0L)) return; /* nothing to do */
- subnet = mask = 0;
- if (data != NULL)
- {
- maskp = NULL;
- if ((subnetp = strchr(data, ',')) != NULL)
- {
- *subnetp++ = 0;
- if (maskp = strchr(subnetp, ','))
- {
- *maskp++ = 0;
- mask = aton(maskp);
- subnet = aton(subnetp);
- }
- else
- {
- subnet = aton(subnetp);
- switch ((word)(subnet >> 30) & 0x000f)
- {
- case 0:
- case 1: mask = 0xff000000L; break;
- case 2: mask = 0xfffffe00L; break;
- case 3: mask = 0xffffff00L; break;
- }
- }
- }
- }
-
- if (arp_last_gateway >= MAX_GATE_DATA) return;
-
- for (i = 0; i < arp_last_gateway; i++)
- if (arp_gate_data[i].mask < mask)
- {
- bcopy(&arp_gate_data[i], &arp_gate_data[i+1],
- (arp_last_gateway - i) * sizeof(gate_tables));
- break;
- }
-
- if ((data != NULL) && (ip == 0L)) /* if text form given */
- ip = aton(data); /* convert to 32 bit long */
-
- arp_gate_data[i].gate_ip = ip;
- arp_gate_data[i].subnet = subnet;
- arp_gate_data[i].mask = mask;
- arp_last_gateway++; /* used up another one */
- }
-
- longword
- arp_rpt_gateway(int i) /* report IP of gateway i */
- {
- if (i >= 0 && i < MAX_GATE_DATA)
- return (arp_gate_data[i].gate_ip);
- else return (0L);
- }
-
- static void
- arp_request(longword ip)
- {
- register arp_header *op;
- longword temp;
-
- if (ip == my_ip_addr)
- return;
- op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_ARP);
- op->hwType = htons(arp_hardware); /* hardware frame */
- op->protType = TYPE_IP; /* IP protocol */
- op->hlen = (byte)(MAC_len & 0xff); /* MAC address len */
- op->plen = PLEN; /* IP address len */
- op->opcode = ARP_REQUEST;
- bcopy(eth_addr, op->addr, MAC_len); /* our MAC address */
- temp = htonl(my_ip_addr);
- bcopy(&temp, &op->addr[MAC_len], PLEN); /* our IP */
- temp = htonl(ip);
- bcopy(&temp, &op->addr[2*MAC_len+PLEN], PLEN); /* host IP */
- eth_send(sizeof(arp_header)); /* send the packet */
- }
-
- static arp_tables *
- arp_search(longword ip, int create)
- {
- register int i;
- register arp_tables *arp_ptr;
-
- for (i = 0; i < MAX_ARP_DATA; i++)
- if (ip == arp_data[i].ip)
- return(&arp_data[i]);
- /* didn't find any */
- if (create != 0)
- { /* pick an old or empty one */
- for (i = 0; i < MAX_ARP_DATA; i++)
- {
- arp_ptr = &arp_data[i];
- if ((arp_ptr->ip == 0L) ||
- chk_timeout(arp_ptr->expiry + MAX_ARP_GRACE))
- return(arp_ptr);
- }
- /* pick one at pseudo-random */
- return (&arp_data[arp_index =
- (arp_index + 1) % MAX_ARP_DATA]);
- }
- return (NULL);
- }
-
- void
- arp_register(longword use, longword instead_of)
- { /* new IP to use instead of this IP */
- register arp_tables *arp_ptr;
-
- if (arp_ptr = arp_search(instead_of, 0)) /* if in ARP cache */
- { /* insert Ethernet address of new IP */
- arp_resolve(use, arp_ptr->hardware);
- arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
- return;
- }
- arp_ptr = arp_search(use, 1); /* create a new one */
- arp_ptr->flags = ARP_FLAG_NEED;
- arp_ptr->ip = instead_of;
- arp_resolve(use, arp_ptr->hardware);
- arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
- }
-
- void
- arp_tick(longword ip)
- {
- register arp_tables *arp_ptr;
-
- if (arp_ptr = arp_search(ip, 0))
- arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
- }
-
- /*
- * arp_handler - handle incomming ARP packets
- */
- int
- arp_handler(arp_header *in)
- {
- register arp_header *op;
- longword his_ip, temp;
- register arp_tables *arp_ptr;
-
- if (in == NULL) return (0); /* failure */
-
- if (in->protType != TYPE_IP) /* IP protocol */
- return(0); /* 0 means no, fail */
-
- /* continuously accept data - but only for people we talk to */
- bcopy(&in->addr[MAC_len], &his_ip, PLEN);
- his_ip = ntohl(his_ip);
-
- if ((arp_ptr = arp_search(his_ip, 0)) != NULL)/* do not create entry */
- {
- arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
- bcopy(in->addr, arp_ptr->hardware, MAC_len);
- arp_ptr->flags = ARP_FLAG_FOUND;
- }
-
- /* does someone else want our hardware address? */
- bcopy(&in->addr[2*MAC_len+PLEN], &temp, PLEN);
- if (in->opcode == ARP_REQUEST && /* and be a resolution req */
- temp == htonl(my_ip_addr)) /* for my IP */
- {
- op = (arp_header *)eth_formatpacket(in->addr, TYPE_ARP);
- op->hwType = htons(arp_hardware);
- op->protType = TYPE_IP; /* IP protocol */
- op->hlen = (byte) (MAC_len & 0xff); /* MAC address len */
- op->plen = PLEN; /* IP address len */
- op->opcode = ARP_REPLY;
- /* host's MAC and IP address */
- bcopy(in->addr, &op->addr[MAC_len+PLEN], MAC_len + PLEN);
- bcopy(eth_addr, op->addr, MAC_len); /* our MAC addr */
- temp = htonl(my_ip_addr); /* our IP in net order */
- bcopy(&temp, &op->addr[MAC_len], PLEN);
- return (eth_send(sizeof(arp_header))); /* send the packet */
- }
- return (1); /* for success */
- }
-
- /*
- * arp_resolve - resolve IP address to hardware address
- */
- int
- arp_resolve(longword ina, eth_address *ethap)
- {
- register arp_tables *arp_ptr;
- register word i;
- int j;
- longword timeout, resend;
- static int recurse = 0;
-
- /* If we are running SLIP or ODI's SLIP_PPP which do not use
- MAC level addresses */
- if (pktdevclass == PD_SLIP ||
- (pktdevclass == PD_ETHER && MAC_len == 0 ))
- return(1);
-
- if (ina == my_ip_addr)
- {
- if (ethap != NULL)
- bcopy(eth_addr, ethap, MAC_len);
- recurse = 0;
- return(1); /* success */
- }
- if (ina == 0L || ina == 0xffffffffL || ina == ipbcast)
- return (0); /* cannot resolve IP of 0's or 0xff's*/
-
- if (recurse > 6) return (0); /* fail */
- recurse++;
- tcp_tick(NULL);
- /* attempt to solve with ARP cache */
- if ((arp_ptr = arp_search(ina, 0)) != NULL)
- if (strncmp(arp_ptr->hardware, eth_none, MAC_len))
- { /* have non-NULL Ethernet address */
- /* has been resolved */
- #ifdef NEW_EXPIRY
- if (chk_timeout(arp_ptr->expiry))
- {
- if (! chk_timeout(arp_ptr->expiry +
- MAX_ARP_GRACE))
- /* we wish to refresh it asynchronously */
- arp_request(ina);
- }
- #endif /* NEW_EXPIRY */
- if ((arp_ptr->flags == ARP_FLAG_FOUND) ||
- (arp_ptr->flags == ARP_FLAG_FIXED))
- {
- /* we found a valid hardware address */
- if (ethap != NULL)
- {
- bcopy(arp_ptr->hardware, ethap,
- MAC_len);
- recurse = 0;
- return(1); /* success */
- }
- } /* end of if ((arp_ptr... */
- } /* end of if (strncmp... main */
-
- /* make a new one if necessary */
- if (arp_ptr == NULL)
- {
- arp_ptr = arp_search(ina, 1); /* 1 means create an entry */
- arp_ptr->flags = ARP_FLAG_NEED; /* say need a real entry */
- }
-
- /* we must look elsewhere - but is it on our subnet? */
- if ((ina ^ my_ip_addr) & sin_mask) /* not of this network */
- {
- j = 0; /* init status return */
- for (i = 0; i < arp_last_gateway; i++)
- { /* compare the various subnet bits */
- if ((arp_gate_data[i].mask & ina) ==
- arp_gate_data[i].subnet)
- /* watch out RECURSIVE CALL! */
- if ((j = arp_resolve(arp_gate_data[i].gate_ip,
- ethap)) != 0)
- break; /* success */
- }
- recurse--;
- return (j);
- }
-
- if (ina == 0L) /* return if no host, or no gateway */
- {
- recurse--;
- outs("\r\n Cannot find a gateway");
- return(0); /* fail */
- }
-
- /* is on our subnet, we must resolve */
- timeout = set_timeout(2); /* two seconds is long for ARP */
- while (!chk_timeout(timeout))
- { /* do the request */
- arp_request(arp_ptr->ip = ina);
- resend = set_timeout(1) - 14L; /* 250 ms */
- while (!chk_timeout(resend))
- {
- tcp_tick(NULL); /* read packets */
- if (arp_ptr->flags)
- {
- if (ethap != NULL)
- bcopy(arp_ptr->hardware, ethap,
- MAC_len);
- arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
- arp_ptr->flags = ARP_FLAG_FOUND;
- recurse = 0;
- return(1); /* success */
- }
- }
- }
- recurse--;
- return(0); /* fail */
- }
-
-
- int
- rarp_handler(arp_header *in)
- {
- register word i;
- longword his_ip;
- register arp_tables *arp_ptr;
-
- if (in == NULL) return (0); /* failure */
-
- if ((in->protType != TYPE_IP)) /* Internet protocol*/
- return (0); /* 0 means no, fail */
- bcopy(&in->addr[MAC_len], &his_ip, PLEN);
- his_ip = ntohl(his_ip);
- if ((arp_ptr = arp_search(his_ip, 0)) != NULL)
- {
- arp_ptr->expiry = set_timeout(MAX_ARP_ALIVE);
- bcopy(in->addr, arp_ptr->hardware, MAC_len);
- arp_ptr->flags = ARP_FLAG_FOUND;
- }
- /* look for RARP Reply */
- if ((my_ip_addr == 0) && (in->opcode == RARP_REPLY))
- { /* match our Ethernet address too */
- for (i = 0; i < MAC_len; i++)
- if (in->addr[i+MAC_len+PLEN] != (byte)eth_addr[i])
- return (1); /* not for us */
- bcopy(&in->addr[2*MAC_len+PLEN], &my_ip_addr, PLEN);
- my_ip_addr = ntohl(my_ip_addr); /* our IP addr */
- }
- return (1); /* for success */
- }
-
- /* send a RARP packet to request an IP address for our MAC address */
- static void
- arp_rev_request(void)
- {
- register arp_header *op;
-
- op = (arp_header *)eth_formatpacket(ð_brdcast[0], TYPE_RARP);
- op->hwType = htons(arp_hardware);
- op->protType = TYPE_IP; /* IP protocol */
- op->hlen = (byte)(MAC_len & 0xff); /* MAC address len */
- op->plen = PLEN; /* IP address len */
- op->opcode = RARP_REQUEST;
- bcopy(eth_addr, op->addr, MAC_len); /* our MAC address */
- bcopy(eth_addr, &op->addr[MAC_len+PLEN], MAC_len); /* in target too */
- eth_send(sizeof(arp_header)); /* send the packet */
- }
-
- /* Send a series of RARP requests until our IP address is non-zero or
- we timeout.
- */
- int
- do_rarp(void)
- {
- longword timeout, resend;
-
- timeout = set_timeout(10); /* 10 seconds total */
- while (chk_timeout(timeout) == 0)
- {
- arp_rev_request(); /* ask for our IP */
- resend = set_timeout(1); /* two second retry */
- while (chk_timeout(resend) == 0)
- {
- tcp_tick(NULL); /* read packets */
- if (my_ip_addr != 0L) return (1); /* got a reply */
- }
- }
- return (0); /* got no reply */
- }
-